/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package control;

import it.polimi.se2.meteocal.control.CalendarManager;
import it.polimi.se2.meteocal.control.EmailSender;
import it.polimi.se2.meteocal.control.EventManager;
import it.polimi.se2.meteocal.control.LocationManager;
import it.polimi.se2.meteocal.control.NotificationManager;
import it.polimi.se2.meteocal.control.ParticipationManager;
import it.polimi.se2.meteocal.control.UserManager;
import it.polimi.se2.meteocal.control.WeatherManager;
import it.polimi.se2.meteocal.control.WeatherSchedule;
import it.polimi.se2.meteocal.entity.Event;
import it.polimi.se2.meteocal.entity.EventNotification;
import it.polimi.se2.meteocal.entity.Location;
import it.polimi.se2.meteocal.entity.Participation;
import it.polimi.se2.meteocal.entity.ParticipationNotification;
import it.polimi.se2.meteocal.entity.Users;
import it.polimi.se2.meteocal.entity.Weather;
import it.polimi.se2.meteocal.helper.DateUtilityMethods;
import java.sql.Time;
import java.util.List;
import javax.ejb.EJB;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.arquillian.junit.InSequence;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;

/**
 *
 * @author Ugo
 */
@RunWith(Arquillian.class)
public class WeatherScheduleIT {
    
    private WeatherSchedule weatherSchedule=new WeatherSchedule();
    
   
    @EJB
    LocationManager locationManager;
    @EJB
    EventManager eventManager;
    @EJB
    NotificationManager notificationManager;
    @EJB
    UserManager userManager;
    @EJB
    WeatherManager weatherManager;
    @EJB
    CalendarManager calendarManager;
    @EJB
    ParticipationManager participationManager;
    
    
    private final Users user1=new Users();
    private final Users user2 = new Users();
    private Event event3;
    
    public WeatherScheduleIT() {
    }
    
   
    @Deployment
    public static WebArchive createArchiveAndDeploy() {
        return ShrinkWrap.create(WebArchive.class)
                .addClass(EventManager.class)
                .addClass(UserManager.class)
                .addClass(NotificationManager.class)
                .addClass(CalendarManager.class)
                .addClass(WeatherManager.class)
                .addClass(WeatherSchedule.class)
                .addClass(LocationManager.class)
                .addClass(ParticipationManager.class)
                .addPackage(Event.class.getPackage())
                .addAsResource("test-persistence.xml", "META-INF/persistence.xml")
                .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    
    
    @Test
    @InSequence(1)
    public void  newEventAndLoadWeatherCondition(){
        //INIT
        weatherSchedule=new WeatherSchedule();
        weatherSchedule.setParticipationManager(participationManager);
        weatherSchedule.setEventManager(eventManager);
        weatherSchedule.setNotificationManager(notificationManager);
        weatherSchedule.setLocationManager(locationManager);
        weatherSchedule.setWeatherManager(weatherManager);
        //
        
        user1.setEmail("ugodevos@gmail.com");
        user1.setName("Paolo");
        user1.setSurname("Rossi");
        user1.setPassword("password");
        user1.setCity("city");
        userManager.save(user1);
        Event event=new Event();
        event.setCalendar(calendarManager.findCalendarByUser(user1));
        event.setTitle("Run");
        java.util.Calendar today= java.util.Calendar.getInstance();
        event.setData(today.getTime());
        event.setBeginn(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        event.setEndd(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        locationManager.create(new Location("Milano"));
        event.setLocation(new Location("Milano"));
        event.setOutdoor(true);
        event.setPrivatee(false);
        eventManager.create(event);
        
       
        weatherSchedule.checkWeatherConditions();
        
        Weather weather,weather8days;
        
        weather= weatherManager.getWeatherByLocationAndDate(event.getLocation(), event.getData());
        assertNotNull(weather);
        
        java.util.Calendar up8days= java.util.Calendar.getInstance();
        up8days.add(java.util.Calendar.DAY_OF_YEAR, 8);
        weather8days= weatherManager.getWeatherByLocationAndDate(event.getLocation(), up8days.getTime());
        assertNotNull(weather8days);
       
        
        List<Weather> weathercomplete = weatherManager.getWeatherByLocation(event.getLocation());
        assertTrue(weathercomplete.size()>=10);
        
        java.util.Calendar yesterday= java.util.Calendar.getInstance();
        yesterday.add(java.util.Calendar.DAY_OF_YEAR, -1);
        Weather weather2 = weatherManager.getWeatherByLocationAndDate(event.getLocation(),yesterday.getTime() );
        assertNull(weather2);
    }
    
    @Test
    @InSequence(2)
    public void day1Notification(){
        weatherSchedule=new WeatherSchedule();
        weatherSchedule.setParticipationManager(participationManager);
        weatherSchedule.setEventManager(eventManager);
        weatherSchedule.setNotificationManager(notificationManager);
        weatherSchedule.setLocationManager(locationManager);
        weatherSchedule.setWeatherManager(weatherManager);
        
        user2.setEmail("arydv_94@hotmail.it");
        user2.setName("Barbara");
        user2.setSurname("Bianchi");
        user2.setPassword("password");
        user2.setCity("city");
        userManager.save(user2);
        
        Event event2=new Event();
        event2.setCalendar(calendarManager.findCalendarByUser(userManager.findUserByEmail("ugodevos@gmail.com")));
        event2.setTitle("Run");
        java.util.Calendar today= java.util.Calendar.getInstance();
        today.add(java.util.Calendar.DAY_OF_YEAR, 1);
        event2.setData(today.getTime());
        event2.setBeginn(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        event2.setEndd(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        locationManager.create(new Location("Milano"));
        event2.setLocation(new Location("Milano"));
        event2.setOutdoor(true);
        event2.setPrivatee(false);
        eventManager.create(event2);
       
        Participation part=new Participation();
        part.setEvent(event2);
        part.setUser(user2);
        participationManager.create(part);
        
        Weather weatheractual = weatherManager.getWeatherByLocationAndDate(event2.getLocation(), event2.getData());
        weatheractual.setDescription("sunny");
        weatherManager.edit(weatheractual);
        weatherSchedule.check1dayBadWeather();
        
        List<ParticipationNotification> partnot=notificationManager.findParticipationNotificationByParticipation(part);
       
        assertEquals(partnot.size(),0);
        
        weatheractual = weatherManager.getWeatherByLocationAndDate(event2.getLocation(), event2.getData());
        weatheractual.setDescription("snow");
        weatherManager.edit(weatheractual);
        weatherSchedule.check1dayBadWeather();
        
        partnot=null;
        partnot=notificationManager.findParticipationNotificationByUser3(user2);
        assertNotNull(partnot);
     
    }
    
    @Test
    @InSequence(3)
    public void day3Notification(){
        weatherSchedule=new WeatherSchedule();
        weatherSchedule.setParticipationManager(participationManager);
        weatherSchedule.setEventManager(eventManager);
        weatherSchedule.setNotificationManager(notificationManager);
        weatherSchedule.setLocationManager(locationManager);
        weatherSchedule.setWeatherManager(weatherManager);
        
        event3=new Event();
        event3.setCalendar(calendarManager.findCalendarByUser(userManager.findUserByEmail("ugodevos@gmail.com")));
        event3.setTitle("Run");
        java.util.Calendar today= java.util.Calendar.getInstance();
        today.add(java.util.Calendar.DAY_OF_YEAR, 3);
        event3.setData(today.getTime());
        event3.setBeginn(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        event3.setEndd(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        locationManager.create(new Location("Bologna"));
        event3.setLocation(new Location("Bologna"));
        event3.setOutdoor(true);
        event3.setPrivatee(false);
        eventManager.create(event3);
        
        weatherSchedule.checkWeatherConditions();
        
        Weather weatheractual = weatherManager.getWeatherByLocationAndDate(event3.getLocation(), event3.getData());   
        weatheractual.setDescription("sunny");
        weatherManager.edit(weatheractual);
        check3daysBadWeather();
        EventNotification eventnot=notificationManager.findEventNotificationByEvent(event3);
        assertNull(eventnot);
        
        weatheractual.setDescription("snow");
        weatherManager.edit(weatheractual);
        today.add(java.util.Calendar.DAY_OF_YEAR, 1);
        Weather weather4gg = weatherManager.getWeatherByLocationAndDate(event3.getLocation(),today.getTime() );   
        weather4gg.setDescription("snow");
        weatherManager.edit(weather4gg);
        today.add(java.util.Calendar.DAY_OF_YEAR, 1);
        Weather weather5gg = weatherManager.getWeatherByLocationAndDate(event3.getLocation(),today.getTime() );   
        weather5gg.setDescription("hurricane");
        weatherManager.edit(weather5gg);
        today.add(java.util.Calendar.DAY_OF_YEAR, 1);
        Weather weather6gg = weatherManager.getWeatherByLocationAndDate(event3.getLocation(),today.getTime() );   
        weather6gg.setDescription("sky is clear");
        weatherManager.edit(weather6gg);
        check3daysBadWeather();
        
        eventnot=notificationManager.findEventNotificationByEvent(event3);
        assertNotNull(eventnot);
        // today contiene la data di oggi sommati 6 gg ossia il primo giorno successivo con bel tempo
        assertEquals(eventnot.getNewdate().getDate(),today.getTime().getDate());
        
        //overwriteDay3Notification
        java.util.Calendar today2= java.util.Calendar.getInstance();
        today2.add(java.util.Calendar.DAY_OF_YEAR, 4);
        weather4gg = weatherManager.getWeatherByLocationAndDate(event3.getLocation(),today2.getTime() );   
        weather4gg.setDescription("sky is clear");
        weatherManager.edit(weather4gg);
        check3daysBadWeather();
        
        eventnot=notificationManager.findEventNotificationByEvent(event3);
        assertEquals(eventnot.getNewdate().getDate(),today2.getTime().getDate());
        // la nuova best date deve essere diminuita di 2 gg
      
    }
       
    @Test
    @InSequence(4)
    public void outdoorEvent(){
        weatherSchedule=new WeatherSchedule();
        weatherSchedule.setParticipationManager(participationManager);
        weatherSchedule.setEventManager(eventManager);
        weatherSchedule.setNotificationManager(notificationManager);
        weatherSchedule.setLocationManager(locationManager);
        weatherSchedule.setWeatherManager(weatherManager);
        
        Event event2=new Event();
        event2.setCalendar(calendarManager.findCalendarByUser(userManager.findUserByEmail("ugodevos@gmail.com")));
        event2.setTitle("Run");
        java.util.Calendar today= java.util.Calendar.getInstance();
        today.add(java.util.Calendar.DAY_OF_YEAR, 3);
        event2.setData(today.getTime());
        event2.setBeginn(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        event2.setEndd(new Time(today.getTime().getHours(),today.getTime().getMinutes(),today.getTime().getSeconds()));
        locationManager.create(new Location("Pavia"));
        event2.setLocation(new Location("Pavia"));
        event2.setOutdoor(false); //!!!!
        event2.setPrivatee(false);
        eventManager.create(event2);
        
        weatherSchedule.checkWeatherConditions();
        check3daysBadWeather();
        EventNotification eventnot=notificationManager.findEventNotificationByEvent(event2);
        assertNull(eventnot);
        
    }
    
    private boolean isBadWeather(Weather weather){
        String description = weather.getDescription().toLowerCase();
        if(description.contains("rain")||description.contains("drizzle")||description.contains("thunderstorm")|| description.contains("snow")|| description.contains("tornado") ||description.contains("storm")||description.contains("hurricane")||description.contains("gale"))
            return true;
        return false;
    }   
      
     private void check3daysBadWeather(){
        EmailSender emailSender = new EmailSender();
        System.out.println("Checking events in bad weather conditions - 3 days notification");
        List<Event> events;
        events=eventManager.getAllEvent();
        //checkWeatherConditions();  RIMOSSO PER I TEST 
        for(Event e:events)
        {
            Weather weather= weatherManager.getWeatherByLocationAndDate(e.getLocation(), e.getData());
            if (weather!=null)
            {
                if(e.isOutdoor() && isBadWeather(weather) && DateUtilityMethods.distanceInDaysAccurate(DateUtilityMethods.DateAndTime(e.getData(), e.getBeginn()))<=3.0 && DateUtilityMethods.distanceInDaysAccurate(DateUtilityMethods.DateAndTime(e.getData(), e.getBeginn()))>=2.5)
                {
                    List<Weather> weatherchoices = weatherManager.getWeatherByLocation(e.getLocation());
                    for(Weather w:weatherchoices)
                    {
                      System.out.println(w.getDescription());
                      if(w.getDate().after(e.getData())){
                        if(isBadWeather(w)==false)
                        { 
                            System.out.println("found first date with good conditions in "+ w.getlocation() + " on: "+ w.getDate() + " with: "+w.getDescription() + " for event: " + e.getId());
                            EventNotification eventnot = notificationManager.findEventNotificationByEvent(e);
                            if(eventnot==null){
                                notificationManager.create(new EventNotification(e,w.getDate()));
                                emailSender.sendEmail3daysNotification(e, weather, w.getDate());
                            }
                            else
                            {
                                System.out.println("new research for an event already notified for bad conditions");
                                //se da una seconda analisi si ottiene una data differente, creo una nuova notifica all'owner con la nuova data.altrimenti non lo disturbo
                                if (!w.getDate().equals(eventnot.getNewdate()))
                                {
                                    System.out.println("previous value " +eventnot.getNewdate());
                                    System.out.println("new best date on "+ w.getDate());
                                    eventnot.setNewdate(w.getDate());
                                    eventnot.setSeen(false);
                                    notificationManager.edit(eventnot);
                                    emailSender.sendEmail3daysNotification(e, weather, w.getDate());
                                }
                                else
                                    System.out.println("no changed");
                            }
                            break;
                        }
                       }
                    }
                      weatherchoices=null; 
                }
            }
        }
    }

}
